/* This program and the accompanying materials are dual-licensed under
 * either
 *
 * (a) the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation, or (at your option) any
 * later version.
 *
 * or (per the licensee's choosing)
 *
 * (b) the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation.
 */
package org.jgrapht.demo;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JFrame;

import org.jgrapht.ListenableGraph;
import org.jgrapht.event.GraphEdgeChangeEvent;
import org.jgrapht.event.GraphListener;
import org.jgrapht.event.GraphVertexChangeEvent;
import org.jgrapht.ext.JGraphXAdapter;
import org.jgrapht.graph.DefaultEdge;
import org.jgrapht.graph.ListenableDirectedGraph;

import com.automic.pm.core.DependencyResolver;
import com.automic.pm.core.PackageDependency;
import com.automic.pm.core.PackageInfo;
import com.automic.pm.core.PackageRepository;
import com.automic.pm.versioning.ComparisonOperator;
import com.automic.pm.versioning.DefaultVersion;
import com.google.common.collect.Sets;
import com.mxgraph.layout.mxCircleLayout;
import com.mxgraph.model.mxICell;
import com.mxgraph.swing.mxGraphComponent;


/**
 * A demo applet that shows how to use JGraphX to visualize JGraphT graphs.
 * Applet based on JGraphAdapterDemo.
 *
 * @since July 9, 2013
 */
public class JGraphXAdapterDemo
    extends JApplet
{
    

    private static final long serialVersionUID = 2202072534703043194L;
    private static final Dimension DEFAULT_SIZE = new Dimension(1030, 820);

    private PackageRepository<PackageInfo> graph;
    
    private PackageInfo a = new PackageInfo("a", new DefaultVersion("2.0.0"), new ArrayList<PackageDependency>());
    private PackageInfo b = new PackageInfo("b", new DefaultVersion("2.0.1"), new ArrayList<PackageDependency>());
    private PackageInfo c = new PackageInfo("c", new DefaultVersion("3.1.1"), new ArrayList<PackageDependency>());
    private PackageInfo d31 = new PackageInfo("d", new DefaultVersion("3.1.0"), new ArrayList<PackageDependency>());
    private PackageInfo d32 = new PackageInfo("d", new DefaultVersion("3.2.0"), new ArrayList<PackageDependency>());
    private PackageInfo d33 = new PackageInfo("d", new DefaultVersion("3.3.0"), new ArrayList<PackageDependency>());
    private PackageInfo d34 = new PackageInfo("d", new DefaultVersion("3.4.0"), new ArrayList<PackageDependency>());
    private PackageInfo d35 = new PackageInfo("d", new DefaultVersion("3.5.0"), new ArrayList<PackageDependency>());
    private PackageInfo e = new PackageInfo("e", new DefaultVersion("5.3.0"), new ArrayList<PackageDependency>());
    private PackageInfo f15 = new PackageInfo("f", new DefaultVersion("1.5.0"), new ArrayList<PackageDependency>());
    private PackageInfo f17 = new PackageInfo("f", new DefaultVersion("1.7.0"), new ArrayList<PackageDependency>());
    private PackageInfo h23 = new PackageInfo("h", new DefaultVersion("2.3.1"), new ArrayList<PackageDependency>());
    private PackageInfo h22 = new PackageInfo("h", new DefaultVersion("2.2.1"), new ArrayList<PackageDependency>());
    
    private PackageInfo f13 = new PackageInfo("f", new DefaultVersion("1.3.0"), new ArrayList<PackageDependency>());
    private PackageInfo b10 = new PackageInfo("b", new DefaultVersion("1.0.0"), new ArrayList<PackageDependency>());
    private PackageInfo d21 = new PackageInfo("d", new DefaultVersion("2.1.0"), new ArrayList<PackageDependency>());
    private PackageInfo z = new PackageInfo("z", new DefaultVersion("1.0.0"), new ArrayList<PackageDependency>());
            

    JButton resolveButton = new JButton("Resolve");
    
    private ListenableGraph<PackageInfo, DefaultEdge> visualGraph = new ListenableDirectedGraph<PackageInfo, DefaultEdge>(DefaultEdge.class);
    
    // create a visualization using JGraph, via an adapter
    private JGraphXAdapter<PackageInfo, DefaultEdge> jgxAdapter = new JGraphXAdapter<PackageInfo, DefaultEdge>(visualGraph);

    

    /**
     * An alternative starting point for this demo, to also allow running this
     * applet as an application.
     *
     * @param args ignored.
     */
    public static void main(String [] args)
    {
        JGraphXAdapterDemo applet = new JGraphXAdapterDemo();
        applet.init();

        JFrame frame = new JFrame();
        frame.getContentPane().add(applet);
        frame.setTitle("JGraphT Adapter to JGraph Demo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
    }
    
    public void resolve() {
        DependencyResolver resolver = new DependencyResolver(graph); 
        boolean result = resolver.resolve(a);
        
        Set<PackageInfo> valids = resolver.getValid();
        
        for (PackageInfo vertex : visualGraph.vertexSet()) {
            if (!valids.contains(vertex)) {
                Set<DefaultEdge> edges = visualGraph.edgesOf(vertex);
                if (edges.size() > 0) {
                    visualGraph.removeAllEdges(edges);
                }            
            }
        }
        
        Set<PackageInfo> invalids = Sets.newHashSet(Sets.difference(visualGraph.vertexSet(), valids));
                    
        visualGraph.removeAllVertices(invalids);
    }

    /**
     * {@inheritDoc}
     */
    public void init()
    {
        getContentPane().setLayout(new FlowLayout());
        getContentPane().add(new mxGraphComponent(jgxAdapter));
        getContentPane().add(resolveButton);
        resize(DEFAULT_SIZE);
        
        resolveButton.addActionListener(new ActionListener() {
            
            @Override
            public void actionPerformed(ActionEvent e) {
                resolve();   
                repaint();
            }
        });

        graph = new PackageRepository<>();      
        a.getPackageDependencies().add(new PackageDependency("b", ComparisonOperator.GREATER_THAN_OR_EQUAL_TO, new DefaultVersion("2.0.0")));
        a.getPackageDependencies().add(new PackageDependency("c", ComparisonOperator.GREATER_THAN_OR_EQUAL_TO, new DefaultVersion("3.0.0")));
        a.getPackageDependencies().add(new PackageDependency("h", ComparisonOperator.GREATER_THAN_OR_EQUAL_TO, new DefaultVersion("2.0.0")));
        b.getPackageDependencies().add(new PackageDependency("d", ComparisonOperator.GREATER_THAN_OR_EQUAL_TO, new DefaultVersion("3.2.0")
            , ComparisonOperator.LESS_THAN_OR_EQUAL_TO, new DefaultVersion("4.0.0")));
        c.getPackageDependencies().add(new PackageDependency("d", ComparisonOperator.GREATER_THAN_OR_EQUAL_TO, new DefaultVersion("3.0.0")
            , ComparisonOperator.LESS_THAN_OR_EQUAL_TO, new DefaultVersion("3.4.0")));
        
        d31.getPackageDependencies().add(new PackageDependency("e", ComparisonOperator.GREATER_THAN_OR_EQUAL_TO, new DefaultVersion("5.0.0")));
        d32.getPackageDependencies().add(new PackageDependency("e", ComparisonOperator.GREATER_THAN_OR_EQUAL_TO, new DefaultVersion("5.1.0")));
        d33.getPackageDependencies().add(new PackageDependency("e", ComparisonOperator.GREATER_THAN_OR_EQUAL_TO, new DefaultVersion("5.7.0")));
        d34.getPackageDependencies().add(new PackageDependency("f", ComparisonOperator.GREATER_THAN_OR_EQUAL_TO, new DefaultVersion("1.0.0")));
        d35.getPackageDependencies().add(new PackageDependency("f", ComparisonOperator.GREATER_THAN_OR_EQUAL_TO, new DefaultVersion("1.0.0")));
        f17.getPackageDependencies().add(new PackageDependency("g", ComparisonOperator.GREATER_THAN_OR_EQUAL_TO, new DefaultVersion("2.0.0")));
        h22.getPackageDependencies().add(new PackageDependency("f", ComparisonOperator.GREATER_THAN_OR_EQUAL_TO, new DefaultVersion("1.0")));
        h23.getPackageDependencies().add(new PackageDependency("f", ComparisonOperator.GREATER_THAN_OR_EQUAL_TO, new DefaultVersion("1.6")));
        e.getPackageDependencies().add(new PackageDependency("b", ComparisonOperator.GREATER_THAN_OR_EQUAL_TO , new DefaultVersion("2.0.0")));
        
        graph.addAll(a, b, c, d31, d32, d33, d34, d35, e, f15, f17, h23, h22);
        
        // add some installed nodes
        b10.getPackageDependencies().add(new PackageDependency("d", ComparisonOperator.GREATER_THAN_OR_EQUAL_TO, new DefaultVersion("2.0")));
        //z.addDependency("d", ">=", "3.5");
        
        graph.addInstalledNodes(f13, b10, d21, z);
        
        final List<PackageInfo> installeds = graph.getInstalledNodes();
        
        visualGraph.addGraphListener(new GraphListener<PackageInfo, DefaultEdge>() {
            
            @Override
            public void vertexRemoved(GraphVertexChangeEvent<PackageInfo> arg0) {
                // TODO Auto-generated method stub
                
            }
            
            @Override
            public void vertexAdded(GraphVertexChangeEvent<PackageInfo> arg0) {
                PackageInfo vertex = arg0.getVertex();
                Map<PackageInfo, mxICell> v2cMap = jgxAdapter.getVertexToCellMap();
                if (installeds.contains(vertex)) {                 
                    mxICell cell = v2cMap.get(vertex);
                    //cell.setStyle();
                } else {
                    if (graph.isInstalled(vertex.getName())) {
                        //GraphConstants.setBackground(attr, Color.ORANGE);
                    }
                }
            }
            
            @Override
            public void edgeRemoved(GraphEdgeChangeEvent<PackageInfo, DefaultEdge> arg0) {
                // TODO Auto-generated method stub
                
            }
            
            @Override
            public void edgeAdded(GraphEdgeChangeEvent<PackageInfo, DefaultEdge> arg0) {
                // TODO Auto-generated method stub
                
            }
        });

        for (PackageInfo pkg : graph.getNodes()) {
            visualGraph.addVertex(pkg);
        }
        
        for (PackageInfo pkg : graph.getInstalledNodes()) {
            visualGraph.addVertex(pkg);
        }
        
        for (PackageInfo vertex : visualGraph.vertexSet()) {
            List<PackageDependency> deps = vertex.getPackageDependencies();
            for (PackageDependency dep : deps) {
                for (PackageInfo otherVertext : visualGraph.vertexSet()) {
                    if (dep.validate(otherVertext)) {
                        visualGraph.addEdge(vertex, otherVertext);
                    }
                }
            }
        }        

        // positioning via jgraphx layouts
        
        mxCircleLayout layout = new mxCircleLayout(jgxAdapter);
        
        layout.execute(jgxAdapter.getDefaultParent());

        // that's all there is to it!...
    }
}

//End JGraphXAdapterDemo.java
